# SSL修复 - 必须在其他网络库导入之前执行
import ssl_fix

import sys
import json
import requests
import time
import pymysql
from PyQt5.QtCore import QThread, pyqtSignal, QObject, QTimer
from config import config
from db_connection import DatabaseConnection

class KuaishouAPI(QObject):
    """API通信类"""
    data_received = pyqtSignal(dict)
    error_occurred = pyqtSignal(str)
    progress_log = pyqtSignal(str)
    
    def __init__(self):
        super().__init__()
        self.base_url = "https://app.kwaixiaodian.com/gateway/distribute/galaxy/era/landing/page"
        # 多Cookie配置，支持轮换使用
        self.cookies = [
            "__NSWJ=; appver=13.5.10.9282; browseType=4; c=a; cdidTag=2; cdid_tag=2; cl=0; client_key=56c3713c; countryCode=cn; country_code=cn; cs=false; darkMode=false; deviceBit=0; did=56C17D9C-2C3E-75AC-6B29-152CD2DE865D; didTag=0; did_tag=0; egid=DFP2EAFD23086EF95037695D2030C4B93E46DE9D450A8D61F46CDF3C7C9C7D82; foreign=0; ftt=; gid=DFP2EAFD23086EF95037695D2030C4B93E46DE9D450A8D61F46CDF3C7C9C7D82; global_id=DFPFAA7C74495905F5CDA5954851849B205736A325A02715E6DC6C81789801E3; grant_browse_type=AUTHORIZED; isp=; kpf=IPHONE; kpn=KUAISHOU; kuaishou.api_st=Cg9rdWFpc2hvdS5hcGkuc3QSoAH9ntkZ5lPoFP5UvSd4RiVLmG_75iSbyIJTpxWLbGhCsjDwoOkIzOxFG0kYTNYklbbfbyIxSNaxfc6FNkBYp0KzYTyh0Y0A0szEdmuLg-Xw672CertAuqINcf3XZn1gFeGjTTrj97ENmk2MODOviHL5BW-6TlTZ2oCWk5Sp1I8hV_U1GRqjTGsjgrjweIagaocsHvC5Mb2DEFDZlx8ycklqGhJEJSDbmRFB8aBbsn7UJvfzpQciIIMIzA8BerCzUopUJ4U8e9tvQs84xrekoJ_CzW7c5BSqKAUwAQ; kuaishou.h5_st=Cg5rdWFpc2hvdS5oNS5zdBKgASGcZMQMVPYGIsm4SfPg0OfnFpS_YeiI1hqlOeFQXBRmdoAP4K0b-kA8sV36JJ8dR2ErAdWMZoOE2wRSinZGPPbcXYITxOq22QpXoiLYcFlvofD5bV2AeLt4Py8qN0B7OXB0z063l7NZx0AmVwTupjhLdlWRf6DUBkDABthzwTYaPV3BnVEgCMHeIm1laC3eDZeWiA_F1OxvJyok2Mx-5OAaEgduzxS3De8OcL6wm9oIlLYepiIgPt6EA2xN6TeHNdNv3cDD02ziGTcvWghtzUByeKnrELUoBTAB; kuaishou.sixin.login_st=ChdrdWFpc2hvdS5zaXhpbi5sb2dpbi5zdBKgATrokSKWDL6jItXmmP7QSfjqsANoWzTcven0GPfWU9YMUe6xoKREJ4yPIk0blkwaa9roVGGQx2G8Ktyl559fRVCj8SNzEYhYKMQzrkolRCCbIfVmZ6_aV8_NWcf_UG0kFohlZwertN228UKUN3l3iwocToDXx1nVXWttvofyq9ZijFnVAUmIdPaM2fhVp6LixMJrz24cR9cFZRH2P4DJyKUaElCFD4yoG0dNrMrGMgWk18ADhiIgE7dg5IeuyKVdRtx_CqqWzb_zJ-0rhZ28sLwTf-FJMy0oBTAB; language=zh-Hans%3Bq%3D1%2C%20en%3Bq%3D0.9; lat=; lkvr=; ll=; ll_client_time=0; lon=; mcc=; mod=iPhone9%2C4; net=WIFI; oDid=6505F793-D877-43C9-9778-CA597F84DDDE; odid=6505F793-D877-43C9-9778-CA597F84DDDE; os=15.8.4; power_mode=0; randomDid=6505F793-D877-43C9-9778-CA597F84DDDE; rdid=6505F793-D877-43C9-9778-CA597F84DDDE; session_id=C1EA8BBD-D789-45A7-B37D-F999F8971F27; sh=2208; sid=C1EA8BBD-D789-45A7-B37D-F999F8971F27; sw=1242; sys=iOS_15.8.4; thermal=10000; token=87ac94ea6b184baf942f7a01ee9d550b-4845787679; uQaTag=1%23%23cmWns%3A0-%23swLdgl%3A99%23ecPp%3A79%23cmNt%3A11; ud=4845787679; urlencode_mod=iPhone9%252C4; userId=4845787679; userRecoBit=0; ver=13.5; videoModelCrowdTag=1_10; weblogger_switch="
        ]
        self.current_cookie_index = 0  # 当前使用的Cookie索引
        self.headers = {
            "Host": "app.kwaixiaodian.com",
            "accept": "application/json, text/plain, */*",
            "kpf": "IPHONE_H5",
            "kpn": "KUAISHOU",
            "accept-language": "zh-CN,zh-Hans;q=0.9",
            "origin": "https://app.kwaixiaodian.com",
            "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_8_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Kwai/13.5.10.9282 ISLP/0 StatusHT/20 KDT/PHONE iosSCH/0 TitleHT/44 NetType/WIFI ISDM/0 ICFO/0 locale/zh-Hans CT/0 Yoda/3.2.6 ISLB/0 CoIS/2 ISLM/0 WebViewType/WK BHT/0 AZPREFIX/az3",
            "referer": "https://app.kwaixiaodian.com/web/kwaishop-cps-galaxy-app/landing/rankList?layoutType=4&configurationId=2",
            "content-type": "application/json",
            "Connection": "keep-alive"
        }
        
    @property
    def cookie(self):
        """获取当前Cookie（向后兼容）"""
        if self.cookies and len(self.cookies) > 0:
            return self.cookies[0]
        return ""
        
    def update_cookie(self, new_cookie):
        """更新单个Cookie（向后兼容）"""
        if new_cookie:
            self.cookies = [new_cookie]
            self.current_cookie_index = 0
        
    def update_cookies(self, cookies_list):
        """更新Cookie列表"""
        if cookies_list and any(cookie.strip() for cookie in cookies_list):
            # 过滤掉空字符串
            self.cookies = [cookie.strip() for cookie in cookies_list if cookie.strip()]
            self.current_cookie_index = 0
        
    def get_current_cookie(self):
        """获取当前轮换的Cookie"""
        if not self.cookies:
            return ""
        cookie = self.cookies[self.current_cookie_index]
        # 轮换到下一个Cookie
        self.current_cookie_index = (self.current_cookie_index + 1) % len(self.cookies)
        return cookie
        
    def get_rank_data(self, ext_param):
        """获取排行榜数据"""
        import requests
        import json
        
        # 添加Cookie到请求头（使用轮换机制）
        headers_with_cookie = self.headers.copy()
        current_cookie = self.get_current_cookie()
        headers_with_cookie["Cookie"] = current_cookie
        
        payload = {
            "pageCode": "landingPage",
            "structCode": "rankList",
            "configurationId": "2",
            "extParam": json.dumps(ext_param)
        }
        
        # 打印请求信息用于调试
        msg1 = f"[API请求] 地址: {self.base_url}"
        msg2 = f"[API请求] 参数: {json.dumps(payload, ensure_ascii=False)}"
        msg3 = f"[API请求] Cookie: {current_cookie[:100]}..." if len(current_cookie) > 100 else f"[API请求] Cookie: {current_cookie}"
        print(msg1); print(msg2); print(msg3)
        try:
            self.progress_log.emit(msg1); self.progress_log.emit(msg2)
        except Exception:
            pass
        
        try:
            response = requests.post(self.base_url, headers=headers_with_cookie, json=payload, timeout=15)
            if response.status_code == 200:
                data = response.json()
                self.data_received.emit(data)
            else:
                self.error_occurred.emit(f"请求失败，状态码: {response.status_code}")
        except Exception as e:
            self.error_occurred.emit(f"请求异常: {str(e)}")
            
    def load_more(self, ext_param):
        """加载更多数据"""
        import requests
        import json
        
        # 添加Cookie到请求头（使用轮换机制）
        headers_with_cookie = self.headers.copy()
        current_cookie = self.get_current_cookie()
        headers_with_cookie["Cookie"] = current_cookie
        
        payload = {
            "pageCode": "landingPage",
            "structCode": "rankList",
            "configurationId": "2",
            "sceneCode": "LoadMore",
            "extParam": json.dumps(ext_param)
        }
        
        # 打印请求信息用于调试
        msg1 = f"[API请求] 地址: {self.base_url}"
        msg2 = f"[API请求] 参数: {json.dumps(payload, ensure_ascii=False)}"
        msg3 = f"[API请求] Cookie: {current_cookie[:100]}..." if len(current_cookie) > 100 else f"[API请求] Cookie: {current_cookie}"
        print(msg1); print(msg2); print(msg3)
        try:
            self.progress_log.emit(msg1); self.progress_log.emit(msg2)
        except Exception:
            pass
        
        try:
            response = requests.post(self.base_url, headers=headers_with_cookie, json=payload, timeout=15)
            if response.status_code == 200:
                data = response.json()
                self.data_received.emit(data)
            else:
                self.error_occurred.emit(f"请求失败，状态码: {response.status_code}")
        except Exception as e:
            self.error_occurred.emit(f"请求异常: {str(e)}")

class DataCrawlerAPI(QThread):
    """数据抓取API类，负责从快手平台抓取商品数据并保存到数据库"""
    
    progress_updated = pyqtSignal(str)
    crawl_finished = pyqtSignal()
    error_occurred = pyqtSignal(str)
    # 实时统计信号：已保存商品总数、视频URL总数
    counts_updated = pyqtSignal(int, int)
    
    def __init__(self, db_config, api_instance):
        super().__init__()
        self.db_config = db_config
        self.api = api_instance
        self.running = False
        self.category_ids = None
        self.category_names = None  # 新增：支持类目名称列表
        self.date_range = "30d"
        self.rank_type = "video"
        # 添加统计变量
        self.total_saved_goods = 0  # 总共保存的商品数
        self.total_saved_videos = 0  # 总共保存的视频URL数
        # 添加调试日志控制标志
        self.debug_enabled = False
        
    def stop(self):
        """停止数据抓取任务"""
        self.running = False
        
    def start_crawl(self, category_ids=None, category_names=None, date_range="30d", rank_type="video"):
        """启动数据抓取任务"""
        self.category_ids = category_ids
        self.category_names = category_names  # 新增：保存类目名称列表
        self.date_range = date_range
        self.rank_type = rank_type
        self.start()
        
    def set_debug_enabled(self, enabled):
        """设置调试日志是否启用"""
        self.debug_enabled = enabled
        
    def debug_log(self, message):
        """调试日志输出"""
        if self.debug_enabled:
            self.progress_updated.emit(message)
            
    def error_log(self, message):
        """错误日志输出（红色）"""
        # 发送带有错误前缀的消息，前端会将其显示为红色
        self.progress_updated.emit(f"ERROR: {message}")
        
    def run(self):
        """在后台线程中执行数据抓取任务"""
        try:
            self.running = True
            self.progress_updated.emit("开始连接数据库...")
            
            # 连接数据库
            connection = DatabaseConnection.create_connection(self.db_config)
            
            try:
                with connection.cursor() as cursor:
                    # 表迁移：优先使用最终表名 ks_goods_rank。若存在旧表则自动重命名，便于平滑升级
                    try:
                        cursor.execute("SHOW TABLES LIKE 'ks_goods_rank'")
                        has_new = cursor.fetchone() is not None
                        cursor.execute("SHOW TABLES LIKE 'ks_goodsdata'")
                        has_mid = cursor.fetchone() is not None
                        cursor.execute("SHOW TABLES LIKE 'goodsdata'")
                        has_old = cursor.fetchone() is not None
                        if not has_new:
                            if has_mid:
                                cursor.execute("RENAME TABLE ks_goodsdata TO ks_goods_rank")
                                connection.commit()
                                self.progress_updated.emit("检测到旧表 ks_goodsdata，已自动重命名为 ks_goods_rank")
                            elif has_old:
                                cursor.execute("RENAME TABLE goodsdata TO ks_goods_rank")
                                connection.commit()
                                self.progress_updated.emit("检测到旧表 goodsdata，已自动重命名为 ks_goods_rank")
                    except Exception:
                        # 任意失败均忽略，后续按新表逻辑继续执行
                        pass

                    # 创建表（如果不存在）
                    create_table_sql = """
                    CREATE TABLE IF NOT EXISTS ks_goods_rank (
                        id int NOT NULL AUTO_INCREMENT COMMENT '主键',
                        relItemId varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '商品id',
                        itemTitle varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '标题',
                        itemImgUrl varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '主图URL',
                        zkFinalPrice varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '价格',
                        profitAmount varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '赚多少钱',
                        commissionRate varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '佣金率',
                        videoList text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '视频列表',
                        deleted int NULL DEFAULT 0 COMMENT '删除标志',
                        categoryName varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '类目名称',
                        channelId int NULL DEFAULT NULL COMMENT '类目id',
                        subCategoryName varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '子类目名称',
                        rankType varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '时间范围类型',
                        createDate datetime NULL DEFAULT NULL COMMENT '创建时间',
                        strTime varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '字符串时间',
                        PRIMARY KEY (id),
                        UNIQUE KEY unique_relItemId (relItemId)
                    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;
                    """
                    cursor.execute(create_table_sql)
                    connection.commit()
                    
                    # 确保旧表补充 itemImgUrl 列
                    try:
                        cursor.execute("SHOW COLUMNS FROM ks_goods_rank LIKE 'itemImgUrl'")
                        has_col = cursor.fetchone() is not None
                        if not has_col:
                            cursor.execute("ALTER TABLE ks_goods_rank ADD COLUMN itemImgUrl varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '主图URL' AFTER itemTitle")
                            connection.commit()
                    except Exception:
                        pass
                    
                # 如果没有指定类目ID，则按照指定的12大类目顺序抓取
                if self.category_ids is None and self.category_names is None:
                    self.progress_updated.emit("按照指定的12大类目顺序抓取数据...")
                    # 指定的12大类目顺序
                    specified_categories = [
                        "食品饮料", "家居百货", "女装女鞋", "美妆护肤", "个护清洁", 
                        "医疗保健", "母婴玩具", "茶酒生鲜", "男装男鞋", "运动户外", 
                        "数码家电", "珠宝配饰"
                    ]
                    
                    # 获取所有分类数据
                    all_categories = self.get_all_categories()
                    
                    # 按照指定顺序排列分类
                    ordered_categories = []
                    for cat_name in specified_categories:
                        for cat in all_categories:
                            if cat.get("name") == cat_name:
                                ordered_categories.append(cat)
                                break
                    
                    # 如果有未匹配的分类，添加到末尾
                    for cat in all_categories:
                        if cat not in ordered_categories:
                            ordered_categories.append(cat)
                            
                    category_data = ordered_categories
                    category_ids = [cat["id"] for cat in category_data]
                    category_names = [cat["name"] for cat in category_data]
                elif self.category_names is not None:
                    # 如果指定了类目名称列表，则只抓取这些类目
                    self.progress_updated.emit(f"按照指定的类目抓取数据: {', '.join(self.category_names)}")
                    
                    # 获取所有分类数据
                    all_categories = self.get_all_categories()
                    
                    # 筛选出指定的类目
                    selected_categories = []
                    for cat_name in self.category_names:
                        for cat in all_categories:
                            if cat.get("name") == cat_name:
                                selected_categories.append(cat)
                                break
                    
                    category_data = selected_categories
                    category_ids = [cat["id"] for cat in category_data]
                    category_names = [cat["name"] for cat in category_data]
                else:
                    category_ids = self.category_ids if self.category_ids is not None else []
                    category_names = [f"类目{cat_id}" for cat_id in category_ids]
                
                total_categories = len(category_ids)
                self.progress_updated.emit(f"总共需要处理 {total_categories} 个类目")
                
                for idx, (category_id, category_name) in enumerate(zip(category_ids, category_names)):
                    if not self.running:
                        self.progress_updated.emit("任务已被用户停止")
                        break
                        
                    self.progress_updated.emit(f"处理类目 {idx+1}/{total_categories} ({category_name}, ID: {category_id})...")
                    self.debug_log(f"正在处理类目: {category_name} (ID: {category_id})")
                    
                    # 获取子类目
                    sub_categories = self.get_sub_categories(category_id)
                    if not sub_categories:
                        # 如果没有子类目，直接处理该类目本身
                        self.progress_updated.emit(f"  类目 {category_name} 没有子类目，直接处理该类目...")
                        sub_categories = [{
                            "id": category_id,
                            "name": category_name,
                            "parent_name": category_name
                        }]
                    
                    total_sub_categories = len(sub_categories)
                    self.progress_updated.emit(f"  类目 {category_name} 包含 {total_sub_categories} 个子类目")
                    
                    for sub_idx, sub_category in enumerate(sub_categories):
                        if not self.running:
                            self.progress_updated.emit("任务已被用户停止")
                            break
                            
                        sub_category_id = sub_category['id']
                        sub_category_name = sub_category['name']
                        parent_category_name = sub_category.get('parent_name', category_name)
                        parent_category_id = category_id  # 父类目ID
                        
                        self.progress_updated.emit(f"  处理子类目 {sub_idx+1}/{total_sub_categories} ({sub_category_name}, ID: {sub_category_id})...")
                        self.debug_log(f"正在处理子类目: {sub_category_name} (ID: {sub_category_id}), 父类目: {parent_category_name}")
                        
                        # 按照要求，每个子类目抓取5次，每次20条数据
                        total_saved_count = 0
                        has_data = False  # 标记是否获取到数据
                        
                        for load_count in range(5):  # 抓取5次
                            if not self.running:
                                self.progress_updated.emit("任务已被用户停止")
                                break
                                
                            # 获取商品数据，使用不同的pcursor参数实现加载更多
                            # 构造正确的子类目请求参数
                            ext_param = {
                                "pcursor": str(load_count * 20),
                                "layoutType": "4",
                                "configurationId": "2",
                                "domainType": "video",
                                "channelId": parent_category_id,  # 父类目ID
                                "rankType": self.date_range,
                                "subChannelId": sub_category_id,  # 子类目ID
                                "categoryName": sub_category_name,  # 子类目名称
                                "curRankNum": load_count * 20
                            }
                            
                            # 只有在调试模式下才输出请求参数
                            self.debug_log(f"请求参数: {json.dumps(ext_param, ensure_ascii=False)}")
                            
                            goods_list = self.get_goods_data_with_param(sub_category_id, ext_param)
                            
                            # 检查是否获取到数据
                            if goods_list:
                                has_data = True
                            elif load_count == 0:
                                # 第一次请求就没有数据，说明该子类目可能没有商品
                                self.progress_updated.emit(f"    子类目 {sub_category_name} 暂时没有商品数据")
                                break
                            
                            # 保存商品数据到数据库
                            saved_count = 0
                            if goods_list:
                                for goods in goods_list:
                                    if not self.running:
                                        self.progress_updated.emit("任务已被用户停止")
                                        break
                                        
                                    try:
                                        # 先计算主图（仅用列表返回）
                                        def _norm(u: str) -> str:
                                            try:
                                                if not u:
                                                    return ''
                                                if isinstance(u, str) and u.strip().lower() == 'null':
                                                    return ''
                                                if u.startswith('http://') or u.startswith('https://'):
                                                    return u
                                                uu = u.lstrip('/')
                                                if uu.startswith('t/'):
                                                    uu = uu[2:]
                                                if uu.startswith('ITEM_IMAGE') or 'ITEM_IMAGE-' in uu:
                                                    name = uu.split('/')[-1]
                                                    return f"https://p2-ec.ecukwai.com/bs2/image-kwaishop-product/{name}"
                                                return uu
                                            except Exception:
                                                return ''
                                        item_img_url = goods.get('itemImgUrl') or ''
                                        if not item_img_url:
                                            ls = goods.get('itemImgUrls')
                                            if isinstance(ls, list) and len(ls) > 0:
                                                for img in ls:
                                                    if isinstance(img, str) and img.strip() and img.strip().lower() != 'null':
                                                        item_img_url = img.strip()
                                                        break
                                                    elif isinstance(img, dict) and 'url' in img and isinstance(img['url'], str):
                                                        u = img['url'].strip()
                                                        if u and u.lower() != 'null':
                                                            item_img_url = u
                                                            break
                                                    elif isinstance(img, dict) and 'image' in img and isinstance(img['image'], str):
                                                        u = img['image'].strip()
                                                        if u and u.lower() != 'null':
                                                            item_img_url = u
                                                            break
                                        if not item_img_url:
                                            for _k in ('imgUrl','imageUrl','coverUrl','squareImgUrl'):
                                                _v = goods.get(_k)
                                                if isinstance(_v, str) and _v and _v.strip().lower() != 'null':
                                                    item_img_url = _v.strip(); break
                                                if isinstance(_v, list) and len(_v) > 0:
                                                    for v2 in _v:
                                                        if isinstance(v2, str) and v2.strip() and v2.strip().lower() != 'null':
                                                            item_img_url = v2.strip()
                                                            break
                                                    if item_img_url:
                                                        break
                                                elif isinstance(_v, dict) and 'url' in _v:
                                                    vv = _v.get('url')
                                                    if isinstance(vv, str) and vv.strip() and vv.strip().lower() != 'null':
                                                        item_img_url = vv.strip()
                                                        break
                                                elif isinstance(_v, dict) and 'image' in _v:
                                                    vv = _v.get('image')
                                                    if isinstance(vv, str) and vv.strip() and vv.strip().lower() != 'null':
                                                        item_img_url = vv.strip()
                                                        break
                                        item_img_url = _norm(item_img_url)
                                        # 检查是否已存在。如已存在且主图为空，则补齐更新；否则跳过。
                                        with connection.cursor() as cursor:
                                            # 注意：历史数据可能将字符串 'null' 写入了 itemImgUrl，这里统一视为无图
                                            check_sql = "SELECT id, itemImgUrl FROM ks_goods_rank WHERE relItemId = %s"
                                            cursor.execute(check_sql, (goods['relItemId'],))
                                            row = cursor.fetchone()
                                            if row:
                                                rec_id, cur_img = row[0], row[1] or ''
                                                cur_img_norm = (cur_img or '').strip().lower()
                                                has_valid_img = bool(cur_img_norm) and cur_img_norm != 'null'
                                                if (not has_valid_img) and item_img_url:
                                                    # 同时在SQL层面也把 'null' 当作无图处理
                                                    upd_sql = "UPDATE ks_goods_rank SET itemImgUrl=%s WHERE id=%s AND (itemImgUrl IS NULL OR itemImgUrl='' OR LOWER(itemImgUrl)='null')"
                                                    cursor.execute(upd_sql, (item_img_url, rec_id))
                                                    connection.commit()
                                                    self.progress_updated.emit(f"    已补齐主图: 商品 {goods['relItemId']}")
                                                    continue
                                                else:
                                                    # 已存在且已有主图，跳过
                                                    self.progress_updated.emit(f"    处理警告: 商品 {goods['relItemId']} 已存在数据库中，跳过保存")
                                                    continue
                                        
                                        # 获取商品详情（包括视频列表）
                                        video_list = self.get_product_videos(goods['relItemId'])
                                        
                                        # 添加商品视频请求延时，避免请求过于频繁
                                        if self.running:
                                            product_video_delay = config.get("delay.product_video_delay", 1)
                                            # 确保是整数类型
                                            if isinstance(product_video_delay, (int, float)):
                                                delay_int = int(product_video_delay)
                                            else:
                                                delay_int = 1
                                            if delay_int > 0:  # 只有当延时大于0时才执行
                                                self.debug_log(f"商品视频请求延时 {delay_int} 秒...")
                                                self.sleep(delay_int)
                                        
                                        # 检查是否遇到风控拦截或其他问题
                                        if video_list == "RISK_CONTROL_FAILED":
                                            # 遇到多次风控拦截，保存商品但将deleted设置为3
                                            self.progress_updated.emit(f"    风控失败: 商品 {goods['relItemId']} 因风控拦截被标记为风控失败状态")
                                            
                                            # 保存商品数据，deleted设置为3
                                            with connection.cursor() as cursor:
                                                insert_sql = """
                                                INSERT INTO ks_goods_rank 
                                                (relItemId, itemTitle, itemImgUrl, zkFinalPrice, profitAmount, commissionRate, 
                                                 videoList, categoryName, channelId, subCategoryName, rankType, createDate, strTime, deleted)
                                                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), DATE_FORMAT(NOW(), '%%Y%%m%%d'), 3)
                                                """
                                                cursor.execute(insert_sql, (
                                                    goods['relItemId'], goods['itemTitle'], item_img_url, goods['zkFinalPrice'],
                                                    goods['profitAmount'], goods['commissionRate'],
                                                    json.dumps([], ensure_ascii=False),  # 空的视频列表
                                                    parent_category_name, category_id, sub_category_name, self.date_range
                                                ))
                                            saved_count += 1
                                            self.total_saved_goods += 1
                                            # 不增加视频数量，因为没有视频
                                            # 发出实时统计信号
                                            try:
                                                self.counts_updated.emit(self.total_saved_goods, self.total_saved_videos)
                                            except Exception:
                                                pass
                                            
                                            # 只有在调试模式下才输出保存的数据详情
                                            self.debug_log(f"保存风控失败商品: ID={goods['relItemId']}, 标题={goods['itemTitle']}, 佣金率={goods['commissionRate']}, 类目={parent_category_name}, deleted=3")
                                            
                                            connection.commit()
                                            continue
                                        
                                        # 检查是否获取到有效的视频数据
                                        if not video_list:
                                            self.progress_updated.emit(f"    处理警告: 商品 {goods['relItemId']} 未获取到视频数据，但仍保存商品信息")
                                        
                                        # 注释掉商品视频列表的日志信息
                                        # self.debug_log(f"商品 {goods['relItemId']} 的视频列表: {video_list}")
                                        
                                        # 插入数据，注意categoryName使用父类目名称
                                        with connection.cursor() as cursor:
                                            insert_sql = """
                                            INSERT INTO ks_goods_rank 
                                            (relItemId, itemTitle, itemImgUrl, zkFinalPrice, profitAmount, commissionRate, 
                                             videoList, categoryName, channelId, subCategoryName, rankType, createDate, strTime, deleted)
                                            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), DATE_FORMAT(NOW(), '%%Y%%m%%d'), 0)
                                            """
                                            # 确保video_list不为None
                                            video_list_json = json.dumps(video_list if video_list is not None else [], ensure_ascii=False)
                                            cursor.execute(insert_sql, (
                                                goods['relItemId'], goods['itemTitle'], item_img_url, goods['zkFinalPrice'],
                                                goods['profitAmount'], goods['commissionRate'],
                                                video_list_json,
                                                parent_category_name, category_id, sub_category_name, self.date_range  # 使用父类目名称
                                            ))
                                            saved_count += 1
                                            # 更新统计信息
                                            self.total_saved_goods += 1
                                            self.total_saved_videos += len(video_list if video_list is not None else [])
                                            # 发出实时统计信号
                                            try:
                                                self.counts_updated.emit(self.total_saved_goods, self.total_saved_videos)
                                            except Exception:
                                                pass
                                            
                                            # 只有在调试模式下才输出保存的数据详情
                                            self.debug_log(f"保存商品数据: ID={goods['relItemId']}, 标题={goods['itemTitle']}, 佣金率={goods['commissionRate']}, 类目={parent_category_name}")
                                            
                                        connection.commit()
                                    except Exception as e:
                                        connection.rollback()  # 回滚事务
                                        # 检查是否为重复键错误
                                        error_str = str(e)
                                        if "Duplicate entry" in error_str and "for key" in error_str:
                                            # 根据用户记忆规范，必须打印日志进行提醒
                                            self.progress_updated.emit(f"    重复商品ID提醒: 商品 {goods['relItemId']} 已存在数据库中，跳过保存")
                                        else:
                                            self.progress_updated.emit(f"    保存商品 {goods['relItemId']} 时出错: {error_str}")
                                        
                                total_saved_count += saved_count
                                # 实时显示统计信息，使用与ProgressDialog匹配的格式
                                self.progress_updated.emit(f"    第{load_count+1}次抓取保存了 {saved_count} 个商品 (总计: {self.total_saved_goods} 个商品, {self.total_saved_videos} 个视频)")
                            else:
                                # 即使没有获取到商品数据，也发送统计信息更新，使用与ProgressDialog匹配的格式
                                self.progress_updated.emit(f"    第{load_count+1}次抓取没有获取到商品数据 (总计: {self.total_saved_goods} 个商品, {self.total_saved_videos} 个视频)")
                            
                            # 添加延时，避免请求过于频繁
                            if self.running and load_count < 4:
                                delay = config.get("delay.goods_delay", 1)
                                # 确保是整数类型
                                if isinstance(delay, (int, float)):
                                    delay_int = int(delay)
                                else:
                                    delay_int = 1
                                self.progress_updated.emit(f"    暂停{delay_int}秒避免请求过于频繁...")
                                self.sleep(delay_int)  # 暂停指定秒数
                                
                        if has_data:
                            self.progress_updated.emit(f"    子类目 {sub_category_name} 总共保存了 {total_saved_count} 个商品 (总计: {self.total_saved_goods} 个商品, {self.total_saved_videos} 个视频)")
                        else:
                            self.progress_updated.emit(f"    子类目 {sub_category_name} 没有商品数据，跳过处理 (总计: {self.total_saved_goods} 个商品, {self.total_saved_videos} 个视频)")
                        
                        # 添加延迟，避免请求过于频繁
                        if self.running and sub_idx < len(sub_categories) - 1:
                            delay = config.get("delay.subcategory_delay", 2)
                            # 确保delay是整数类型
                            delay_int = 2
                            if delay is not None:
                                try:
                                    if isinstance(delay, dict):
                                        delay_value = delay.get("value", 2)
                                        delay_int = int(delay_value) if delay_value is not None else 2
                                    else:
                                        delay_int = int(delay)
                                except (ValueError, TypeError):
                                    delay_int = 2
                            self.progress_updated.emit(f"    暂停{delay_int}秒避免请求过于频繁...")
                            self.sleep(delay_int)  # 暂停指定秒数
                        
                    # 添加延迟，避免请求过于频繁
                    if self.running and idx < len(category_ids) - 1:
                        delay = config.get("delay.category_delay", 3)
                        # 确保delay是整数类型
                        delay_int = 3
                        if delay is not None:
                            try:
                                if isinstance(delay, dict):
                                    delay_value = delay.get("value", 3)
                                    delay_int = int(delay_value) if delay_value is not None else 3
                                else:
                                    delay_int = int(delay)
                            except (ValueError, TypeError):
                                delay_int = 3
                            # 修改消息格式以匹配ProgressDialog的正则表达式
                            self.progress_updated.emit(f"  暂停{delay_int}秒避免请求过于频繁... (总计: {self.total_saved_goods} 个商品, {self.total_saved_videos} 个视频)")
                            self.sleep(delay_int)  # 暂停指定秒数
                        
            finally:
                connection.close()
                
            if self.running:
                # 显示最终统计信息，使用与ProgressDialog匹配的格式
                self.progress_updated.emit(f"数据抓取完成! 总共保存了 {self.total_saved_goods} 个商品，{self.total_saved_videos} 个视频")
            else:
                self.progress_updated.emit("数据抓取已停止!")
            self.crawl_finished.emit()
            
        except Exception as e:
            self.error_occurred.emit(f"数据抓取过程中出错: {str(e)}")
        finally:
            self.running = False

    def get_all_categories(self):
        """获取所有大类目"""
        # 使用API获取真实数据
        try:
            # 使用默认参数获取数据
            ext_param = {
                "layoutType": "4",
                "configurationId": "2",
                "domainType": "total",
                "channelId": 99,
                "rankType": "1h",
                "pcursor": "0",
                "curRankNum": 0
            }
            
            # 直接调用API获取数据
            import requests
            import json
            
            # 添加Cookie到请求头（使用轮换机制）
            headers_with_cookie = self.api.headers.copy()
            current_cookie = self.api.get_current_cookie() if self.api.cookies else ""
            headers_with_cookie["Cookie"] = current_cookie
            
            payload = {
                "pageCode": "landingPage",
                "structCode": "rankList",
                "configurationId": "2",
                "extParam": json.dumps(ext_param)
            }
            
            # 打印请求参数用于调试
            self.debug_log(f"获取分类请求地址: {self.api.base_url}")
            self.debug_log(f"获取分类请求参数: {json.dumps(payload, ensure_ascii=False, indent=2)}")
            self.debug_log(f"获取分类请求Cookie: {current_cookie[:100]}..." if len(current_cookie) > 100 else f"获取分类请求Cookie: {current_cookie}")
            
            # 使用安全的session进行请求
            response = requests.post(
                self.api.base_url, 
                headers=headers_with_cookie, 
                json=payload, 
                timeout=30
            )
                
            self.debug_log(f"获取分类响应状态码: {response.status_code}")
            
            if response.status_code == 200:
                data = response.json()
                # 打印响应数据摘要用于调试
                self.debug_log(f"分类响应数据摘要: result={data.get('result', 'N/A')}")
                
                # 解析分类数据
                categories = self.parse_categories_from_data(data)
                if categories:
                    self.progress_updated.emit(f"成功获取 {len(categories)} 个分类")
                    return categories
                else:
                    # 如果解析失败，返回默认分类（字典格式）
                    self.progress_updated.emit("获取分类数据失败，使用默认分类")
                    return [{"id": 99, "name": "总榜"}]
            else:
                self.progress_updated.emit(f"获取分类数据失败，状态码: {response.status_code}")
                # 打印响应内容用于调试
                try:
                    error_content = response.text[:500]  # 限制打印长度
                    self.debug_log(f"错误响应内容: {error_content}")
                except:
                    pass
                return [{"id": 99, "name": "总榜"}]
        except Exception as e:
            self.progress_updated.emit(f"获取分类数据时出错: {str(e)}")
            # 出错时返回默认分类（字典格式）
            return [{"id": 99, "name": "总榜"}]
            
    def parse_categories_from_data(self, data):
        """从API返回的数据中解析分类信息"""
        try:
            categories = []
            # 从API响应中提取分类数据
            data_section = data.get("data", {})
            data_items = data_section.get("data", {})
            
            # 打印数据结构用于调试
            self.debug_log(f"分类数据结构信息: data_section keys={list(data_section.keys()) if isinstance(data_section, dict) else 'N/A'}")
            
            # 查找category_filter数据
            category_filter = None
            for key, value in data_items.items():
                if key == "category_filter" and "fields" in value:
                    category_filter = value["fields"]
                    break
                    
            if category_filter and "filterList" in category_filter:
                # 提取分类ID和名称
                for category in category_filter["filterList"]:
                    categories.append({
                        "id": category['id'],
                        "name": category['name']
                    })
            
            # 打印解析结果用于调试
            self.debug_log(f"解析分类数据结果: 找到 {len(categories)} 个分类")
            for cat in categories:
                self.debug_log(f"  分类: {cat['name']} (ID: {cat['id']})")
                    
            return categories
        except Exception as e:
            self.progress_updated.emit(f"解析分类数据时出错: {str(e)}")
            return []
            
    def get_sub_categories(self, category_id):
        """获取指定类目下的子类目"""
        # 使用API获取真实数据
        try:
            # 使用指定分类参数获取数据
            ext_param = {
                "layoutType": "4",
                "configurationId": "2",
                "domainType": "total",
                "channelId": category_id,
                "rankType": "1h",
                "pcursor": "0",
                "curRankNum": 0
            }
            
            # 直接调用API获取数据
            import requests
            import json
            
            # 添加Cookie到请求头（使用轮换机制）
            headers_with_cookie = self.api.headers.copy()
            current_cookie = self.api.get_current_cookie() if self.api.cookies else ""
            headers_with_cookie["Cookie"] = current_cookie
            
            payload = {
                "pageCode": "landingPage",
                "structCode": "rankList",
                "configurationId": "2",
                "extParam": json.dumps(ext_param)
            }
            
            # 打印请求参数用于调试
            self.debug_log(f"  获取子分类请求地址: {self.api.base_url}")
            self.debug_log(f"  获取子分类请求参数: {json.dumps(payload, ensure_ascii=False, indent=2)}")
            self.debug_log(f"  获取子分类请求Cookie: {current_cookie[:100]}..." if len(current_cookie) > 100 else f"  获取子分类请求Cookie: {current_cookie}")
            
            response = requests.post(
                self.api.base_url, 
                headers=headers_with_cookie, 
                json=payload, 
                timeout=30
            )
            self.debug_log(f"  获取子分类响应状态码: {response.status_code}")
            
            if response.status_code == 200:
                data = response.json()
                # 打印响应数据摘要用于调试
                self.debug_log(f"  子分类响应数据摘要: result={data.get('result', 'N/A')}")
                
                # 解析子分类数据
                sub_categories = self.parse_sub_categories_from_data(data, category_id)
                self.progress_updated.emit(f"  获取到 {len(sub_categories)} 个子分类")
                return sub_categories
            else:
                self.progress_updated.emit(f"  获取子分类数据失败，状态码: {response.status_code}")
                # 打印响应内容用于调试
                try:
                    error_content = response.text[:500]  # 限制打印长度
                    self.debug_log(f"  错误响应内容: {error_content}")
                except:
                    pass
                return []
        except Exception as e:
            self.progress_updated.emit(f"  获取子分类数据时出错: {str(e)}")
            return []
            
    def parse_sub_categories_from_data(self, data, parent_id):
        """从API返回的数据中解析子分类信息"""
        try:
            sub_categories = []
            # 从API响应中提取分类数据
            data_section = data.get("data", {})
            data_items = data_section.get("data", {})
            
            # 打印数据结构用于调试
            self.debug_log(f"  子分类数据结构信息: data_section keys={list(data_section.keys()) if isinstance(data_section, dict) else 'N/A'}")
            
            # 查找category_filter数据
            category_filter = None
            for key, value in data_items.items():
                if key == "category_filter" and "fields" in value:
                    category_filter = value["fields"]
                    break
                    
            if category_filter and "filterList" in category_filter:
                # 查找指定父分类
                for category in category_filter["filterList"]:
                    if category['id'] == parent_id and 'subList' in category:
                        # 提取子分类
                        for sub_category in category['subList']:
                            sub_categories.append({
                                "id": sub_category['id'],
                                "name": sub_category['name'],
                                "parent_name": category['name']
                            })
                        break
            
            # 打印解析结果用于调试
            self.debug_log(f"  解析子分类数据结果: 找到 {len(sub_categories)} 个子分类")
            for sub_cat in sub_categories:
                self.debug_log(f"    子分类: {sub_cat['name']} (ID: {sub_cat['id']})")
                    
            return sub_categories
        except Exception as e:
            self.progress_updated.emit(f"  解析子分类数据时出错: {str(e)}")
            return []
        
    def get_goods_data_with_param(self, sub_category_id, ext_param):
        """根据指定参数获取子类目下的商品数据"""
        # 使用API获取真实数据
        try:
            # 直接调用API获取数据
            import requests
            import json
            
            # 添加Cookie到请求头（使用轮换机制）
            headers_with_cookie = self.api.headers.copy()
            current_cookie = self.api.get_current_cookie() if self.api.cookies else ""
            headers_with_cookie["Cookie"] = current_cookie
            
            # 构造请求载荷，根据pcursor值决定是否添加sceneCode参数
            payload = {
                "pageCode": "landingPage",
                "structCode": "rankList",
                "configurationId": "2",
                "extParam": json.dumps(ext_param, ensure_ascii=False)
            }
            
            # 如果pcursor不为"0"，则添加sceneCode参数
            if ext_param.get("pcursor", "0") != "0":
                payload["sceneCode"] = "LoadMore"
            
            # 打印请求参数用于调试
            self.debug_log(f"  请求地址: {self.api.base_url}")
            self.debug_log(f"  请求参数: {json.dumps(payload, ensure_ascii=False, indent=2)}")
            self.debug_log(f"  请求Cookie: {current_cookie[:100]}..." if len(current_cookie) > 100 else f"  请求Cookie: {current_cookie}")
            
            response = requests.post(
                self.api.base_url, 
                headers=headers_with_cookie, 
                json=payload, 
                timeout=30
            )
            self.debug_log(f"  响应状态码: {response.status_code}")
            
            if response.status_code == 200:
                data = response.json()
                # 打印响应数据摘要用于调试
                self.debug_log(f"  响应数据摘要: result={data.get('result', 'N/A')}, data keys={list(data.keys()) if isinstance(data, dict) else 'N/A'}")
                
                # 检查数据结构
                if 'data' in data:
                    data_section = data['data']
                    if 'data' in data_section:
                        self.debug_log(f"  数据结构信息: data_section keys={list(data_section.keys()) if isinstance(data_section, dict) else 'N/A'}")
                
                # 解析商品数据
                goods_list = self.parse_goods_data_from_data(data)
                self.progress_updated.emit(f"    获取到 {len(goods_list)} 个商品")
                return goods_list
            else:
                self.progress_updated.emit(f"    获取商品数据失败，状态码: {response.status_code}")
                # 打印响应内容用于调试
                try:
                    error_content = response.text[:500]  # 限制打印长度
                    self.debug_log(f"    错误响应内容: {error_content}")
                except:
                    pass
                return []
        except Exception as e:
            self.progress_updated.emit(f"    获取商品数据时出错: {str(e)}")
            return []
            
    def get_goods_data(self, sub_category_id, date_range, rank_type):
        """获取子类目下的商品数据"""
        # 使用API获取真实数据
        try:
            # 创建一个临时的API实例
            temp_api = KuaishouAPI()
            # 使用指定参数获取数据
            ext_param = {
                "layoutType": "4",
                "configurationId": "2",
                "domainType": "total",
                "channelId": sub_category_id,
                "rankType": date_range,
                "pcursor": "0",
                "curRankNum": 0
            }
            
            # 直接调用API获取数据
            import requests
            import json
            
            # 添加Cookie到请求头（使用轮换机制）
            headers_with_cookie = temp_api.headers.copy()
            current_cookie = temp_api.get_current_cookie() if temp_api.cookies else ""
            headers_with_cookie["Cookie"] = current_cookie
            
            payload = {
                "pageCode": "landingPage",
                "structCode": "rankList",
                "configurationId": "2",
                "extParam": json.dumps(ext_param)
            }
            
            response = requests.post(
                temp_api.base_url, 
                headers=headers_with_cookie, 
                json=payload, 
                timeout=30
            )
            if response.status_code == 200:
                data = response.json()
                # 解析商品数据
                goods_list = self.parse_goods_data_from_data(data)
                self.progress_updated.emit(f"    获取到 {len(goods_list)} 个商品")
                return goods_list
            else:
                self.progress_updated.emit(f"    获取商品数据失败，状态码: {response.status_code}")
                return []
        except Exception as e:
            self.progress_updated.emit(f"    获取商品数据时出错: {str(e)}")
            return []
            
    def parse_goods_data_from_data(self, data):
        """从API返回的数据中解析商品信息"""
        try:
            goods_list = []
            # 从API响应中提取商品数据
            data_section = data.get("data", {})
            data_items = data_section.get("data", {})
            
            # 打印数据结构用于调试
            self.debug_log(f"    数据结构信息: data_section keys={list(data_section.keys()) if isinstance(data_section, dict) else 'N/A'}")
            
            # 查找所有商品卡片数据
            for key, value in data_items.items():
                if key.startswith("CpsGoodsCard_") and "goodsData" in value.get("fields", {}):
                    goods_data = value["fields"]["goodsData"]
                    # 提取需要的字段
                    img = goods_data.get('itemImgUrl')
                    if not img:
                        # 兼容可能的字段名或数组
                        imgs = goods_data.get('itemImgUrls')
                        if isinstance(imgs, list) and imgs:
                            img = imgs[0]
                        else:
                            for k in ('imgUrl','imageUrl','coverUrl','squareImgUrl'):
                                v = goods_data.get(k)
                                if isinstance(v, str) and v:
                                    img = v; break
                                if isinstance(v, list) and v:
                                    img = v[0]; break
                    # 规整图片URL
                    def _norm(u: str) -> str:
                        try:
                            if not u:
                                return ''
                            if isinstance(u, str) and u.strip().lower() == 'null':
                                return ''
                            if u.startswith('http://') or u.startswith('https://'):
                                return u
                            # 去掉前缀 t/ 或 /t/
                            uu = u.lstrip('/')
                            if uu.startswith('t/'):
                                uu = uu[2:]
                            # ITEM_IMAGE-xxxxx -> 拼完整域名
                            if uu.startswith('ITEM_IMAGE') or 'ITEM_IMAGE-' in uu:
                                name = uu.split('/')[-1]
                                return f"https://p2-ec.ecukwai.com/bs2/image-kwaishop-product/{name}"
                            return uu
                        except Exception:
                            return ''
                    img = _norm(img or '')
                    item_data = {
                        "relItemId": goods_data.get('relItemId', ''),
                        "itemTitle": goods_data.get('itemTitle', ''),
                        "itemImgUrl": img or '',
                        "zkFinalPrice": goods_data.get('zkFinalPrice', ''),
                        "profitAmount": goods_data.get('profitAmount', ''),
                        "commissionRate": goods_data.get('commissionRate', '')
                    }
                    # 只有当商品ID不为空时才添加
                    if item_data["relItemId"]:
                        goods_list.append(item_data)
                        if not item_data.get('itemImgUrl'):
                            # 调试：记录缺图时的字段
                            try:
                                self.debug_log(f"[调试] 缺少主图字段: relItemId={item_data['relItemId']} keys={list(goods_data.keys())}")
                            except Exception:
                                pass
            
            # 打印解析结果用于调试
            self.debug_log(f"    解析商品数据结果: 找到 {len(goods_list)} 个商品卡片")
                    
            return goods_list
        except Exception as e:
            self.progress_updated.emit(f"    解析商品数据时出错: {str(e)}")
            return []
        
    def get_product_videos(self, rel_item_id):
        """获取商品的视频列表"""
        # 使用API获取真实数据
        try:
            # 直接调用商品详情API获取数据
            base_url = "https://app.kwaixiaodian.com/gateway/distribute/match/selection/decision/app/info"
            
            # 添加Cookie到请求头（使用轮换机制）
            headers_with_cookie = self.api.headers.copy()
            current_cookie = self.api.get_current_cookie() if self.api.cookies else ""
            headers_with_cookie["Cookie"] = current_cookie
            
            payload = {
                "relItemId": rel_item_id,
                "sceneCode": "selection_decision",
                "themeSceneId": "",
                "relSceneCode": "CPS"
            }
            
            self.debug_log(f"获取商品视频列表请求地址: {base_url}")
            self.debug_log(f"获取商品视频列表请求参数: {json.dumps(payload, ensure_ascii=False)}")
            self.debug_log(f"获取商品视频列表请求Cookie: {current_cookie[:100]}..." if len(current_cookie) > 100 else f"获取商品视频列表请求Cookie: {current_cookie}")
            
            # 阶梯式重试：1秒、5秒、10秒
            retry_delays = [1, 5, 10]
            
            for retry_count in range(3):
                response = requests.post(
                    base_url, 
                    headers=headers_with_cookie, 
                    json=payload, 
                    timeout=30
                )
                self.debug_log(f"获取商品视频列表响应状态码: {response.status_code} (第{retry_count + 1}次尝试)")
                
                if response.status_code == 200:
                    data = response.json()
                    self.debug_log(f"获取商品视频列表响应数据: {json.dumps(data, ensure_ascii=False)[:500]}...")  # 限制打印长度
                    
                    # 检查是否有风控拦截
                    if data.get("result") == 2 and "风控拦截" in data.get("msg", ""):
                        if retry_count < 2:  # 还有重试机会
                            retry_delay = retry_delays[retry_count]
                            # 当遇到风控拦截时用红色日志提醒
                            self.progress_updated.emit(f"错误: 获取商品 {rel_item_id} 视频列表时遇到风控拦截，等待{retry_delay}秒后重试({retry_count + 1}/3)...")
                            self.sleep(retry_delay)  # 阶梯式等待
                            continue
                        else:
                            # 重试次数用完，返回特殊标记
                            self.progress_updated.emit(f"错误: 商品 {rel_item_id} 多次重试后仍遇到风控拦截，将标记为风控失败")
                            return "RISK_CONTROL_FAILED"  # 返回特殊标记表示风控失败
                    
                    # 解析视频列表数据
                    video_list = self.parse_video_list_from_data(data)
                    
                    # 检查是否成功获取到视频数据
                    if not video_list and data.get("result") == 1:
                        # API成功但没有解析到视频，可能是数据结构问题
                        self.debug_log(f"警告: 商品 {rel_item_id} API返回成功但未解析到视频数据，响应结构可能有变化")
                        self.debug_log(f"完整响应数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
                    
                    return video_list
                else:
                    if retry_count < 2:  # 还有重试机会
                        retry_delay = retry_delays[retry_count]
                        self.debug_log(f"获取商品 {rel_item_id} 视频列表失败，状态码: {response.status_code}，准备等待{retry_delay}秒后重试({retry_count + 1}/3)")
                        self.sleep(retry_delay)  # 阶梯式等待
                        continue
                    else:
                        self.debug_log(f"获取商品 {rel_item_id} 视频列表多次失败，状态码: {response.status_code}")
                        return []  # 返回空列表
                        
            # 所有重试都失败了
            self.debug_log(f"获取商品 {rel_item_id} 视频列表重试次数用完")
            return []
            
        except Exception as e:
            self.debug_log(f"获取商品 {rel_item_id} 视频列表时出错: {e}")
            return []
        
    def parse_video_list_from_data(self, data):
        """从API返回的数据中解析视频列表信息"""
        try:
            video_list = []
            # 从API响应中提取视频数据
            data_section = data.get("data", {})
            data_items = data_section.get("data", {})
            
            self.debug_log(f"解析视频列表数据结构: data_section keys={list(data_section.keys()) if isinstance(data_section, dict) else 'N/A'}")
            
            # 查找视频列表数据
            for key, value in data_items.items():
                if key.startswith("mtp_videoList_") and "fields" in value:
                    video_fields = value["fields"]
                    videos = video_fields.get("videoList", [])
                    self.debug_log(f"找到视频列表字段，包含 {len(videos)} 个视频")
                    # 提取视频信息，包括URL和GMV
                    for video in videos:
                        video_url = video.get('videoUrl', '')
                        gmv_of_90 = video.get('gmvOf90', 0)
                        if video_url:
                            video_list.append({
                                'url': video_url,
                                'gmv': gmv_of_90
                            })
                    break
                    
            # 按GMV从高到低排序
            video_list.sort(key=lambda x: x['gmv'], reverse=True)
            
            # 只保留前5个视频的URL
            result = [video['url'] for video in video_list[:5]]
            return result
        except Exception as e:
            self.debug_log(f"解析视频列表数据时出错: {e}")
            return []

